#include "headers.h"

#include "bitmap_funcs.h"

//#include <ole2.h>
//#include <olectl.h>

BOOL (WINAPI *_mempng2dib) (BYTE*, DWORD, BITMAPINFOHEADER**);

MyBitmap::MyBitmap()
{
	dcBmp = 0;
	hBmp = 0;
	bits = 0;
	width = height = 0;
	bitsSave = 0;
}

MyBitmap::MyBitmap(int w, int h)
{
	dcBmp = 0;
	hBmp = 0;
	bits = 0;
	width = height = 0;
	bitsSave = 0;
	allocate(w,h);
}

MyBitmap::MyBitmap(const char *fn, const char *fnAlpha)
{
	dcBmp = 0;
	hBmp = 0;
	bits = 0;
	width = height = 0;
	bitsSave = 0;
	loadFromFile(fn, fnAlpha);
}

MyBitmap::~MyBitmap()
{
	if (bitsSave)
		delete [] bitsSave;
	free();
}

void MyBitmap::makeOpaque()
{
	if (!bits) return;

	for (int i = 0; i < width*height; i++)
		bits[i] |= 0xff000000;
}

/*
void MyBitmap::makeOpaqueRect(int x1, int y1, int x2, int y2)
{
	if (!bits) return;

	for (int i = y1; i < y2; i++)
		for (int j = x1; j < x2; j++)
		{
			int idx = i * width + j;
			bits[idx] |= 0xff000000;
		}
}
*/

void MyBitmap::saveAlpha(int x, int y, int w, int h)
{
	if (bitsSave)
		delete [] bitsSave;

	if (!w) w = width;
	if (!h) h = height;

	bitsSave = new COLOR32[w*h];
	COLOR32 *p1 = bitsSave;

	for (int i = 0; i < h; i++)
	{
		if (i+y < 0) continue;
		if (i+y >= height) break;
		COLOR32 *p2 = bits + (y+i)*width + x;
		for (int j = 0; j < w; j++)
		{
			if (j+x < 0) continue;
			if (j+x >= width) break;
			*p1++ = *p2++;
		}
	}
}

void MyBitmap::restoreAlpha(int x, int y, int w, int h)
{
	if (!bitsSave)
		return;

	if (!w) w = width;
	if (!h) h = height;

	COLOR32 *p1 = bitsSave;

	for (int i = 0; i < h; i++)
	{
		if (i+y < 0) continue;
		if (i+y >= height) break;
		COLOR32 *p2 = bits + (y+i)*width + x;
		for (int j = 0; j < w; j++)
		{
			if (j+x < 0) continue;
			if (j+x >= width) break;
			if ((*p1&0x00ffffff) != (*p2&0x00ffffff))
			{
				*p2 |= 0xff000000;
			} else
			{
				*p2 = (*p2&0x00ffffff) | (*p1&0xff000000);
			}
			++p1;
			++p2;
		}
	}

	delete [] bitsSave;
	bitsSave = 0;
}

/*
void MyBitmap::DrawBits(COLOR32 *inbits, int inw, int inh, int x, int y, int w, int h)
{
	if (!(bits && inbits)) return;

	float kx = (float)inw / w;
	float ky = (float)inh / h;

	if (x+w >= this->getWidth())
		w = this->getWidth() - x;
	if (y+h >= this->getHeight())
		h = this->getHeight() - y;

	for (int i = 0; i < h; i++)
	{
		if (i+y < 0) continue;
		if (i+y >= height) break;
		for (int j = 0; j < w; j++)
		{
			if (j+x < 0) continue;
			if (j+x >= width) break;
			bits[(i+y)*width + (j+x)] = inbits[int(i*ky)*inw + int(j*kx)];
		}
	}
}
*/

/*
void MyBitmap::BlendBits(COLOR32 *inbits, int inw, int inh, int x, int y, int w, int h)
{
	if (!(bits && inbits)) return;

	float kx = (float)inw / w;
	float ky = (float)inh / h;

	if (x+w >= this->getWidth())
		w = this->getWidth() - x;
	if (y+h >= this->getHeight())
		h = this->getHeight() - y;

	for (int i = 0; i < h; i++)
	{
		if (i+y < 0) continue;
		if (i+y >= height) break;
		for (int j = 0; j < w; j++)
		{
			if (j+x < 0) continue;
			if (j+x >= width) break;
			COLOR32 src = inbits[int(i*ky)*inw + int(j*kx)];
			COLOR32 dst = bits[(i+y)*width + (j+x)];
			long alpha = geta(src);
			bits[(i+y)*width + (j+x)] = rgba(
					getr(src)+(255-alpha)*getr(dst)/255,
					getg(src)+(255-alpha)*getg(dst)/255,
					getb(src)+(255-alpha)*getb(dst)/255,
					geta(src)+(255-alpha)*geta(dst)/255
				);
		}
	}
}
*/
void MyBitmap::Blend(MyBitmap *bmp, int x, int y, int w, int h)
{
	if (!(bits && bmp && bmp->bits)) return;

	if (!w) w = bmp->width;
	if (!h) h = bmp->height;
	float kx = (float)bmp->width / w;
	float ky = (float)bmp->height / h;

	if (x+w >= this->getWidth())
		w = this->getWidth() - x;
	if (y+h >= this->getHeight())
		h = this->getHeight() - y;

	for (int i = 0; i < h; i++)
	{
		if (i+y < 0) continue;
		if (i+y >= height) break;
		for (int j = 0; j < w; j++)
		{
			if (j+x < 0) continue;
			if (j+x >= width) break;
			COLOR32 src = bmp->bits[int(i*ky)*bmp->width + int(j*kx)];
			COLOR32 dst = bits[(i+y)*width + (j+x)];
			long alpha = geta(src);
			bits[(i+y)*width + (j+x)] = rgba(
					getr(src)+(255-alpha)*getr(dst)/255,
					getg(src)+(255-alpha)*getg(dst)/255,
					getb(src)+(255-alpha)*getb(dst)/255,
					geta(src)+(255-alpha)*geta(dst)/255
				);
		}
	}
}

/*
void MyBitmap::Draw(MyBitmap *bmp, int x, int y, int w, int h)
{
	if (!(bits && bmp && bmp->bits)) return;

	if (!w) w = bmp->width;
	if (!h) h = bmp->height;
	float kx = (float)bmp->width / w;
	float ky = (float)bmp->height / h;

	if (x+w >= this->getWidth())
		w = this->getWidth() - x;
	if (y+h >= this->getHeight())
		h = this->getHeight() - y;

	for (int i = 0; i < h; i++)
	{
		if (i+y < 0) continue;
		if (i+y >= height) break;
		for (int j = 0; j < w; j++)
		{
			if (j+x < 0) continue;
			if (j+x >= width) break;
			bits[(i+y)*width + (j+x)] = bmp->bits[int(i*ky)*bmp->width + int(j*kx)];
		}
	}
}
*/

/*
void MyBitmap::BlendColorized(MyBitmap *bmp, int x, int y, int w, int h, COLOR32 color)
{
	if (!(bits && bmp && bmp->bits)) return;

	if (!w) w = bmp->width;
	if (!h) h = bmp->height;
	float kx = (float)bmp->width / w;
	float ky = (float)bmp->height / h;

	// we should swap B and R channels when working with win32 COLORREF
	float koef1r = (255 - getb(color)) / 128.0;
	float koef1g = (255 - getg(color)) / 128.0;
	float koef1b = (255 - getr(color)) / 128.0;

	int br = - 255 + 2 * getb(color);
	int bg = - 255 + 2 * getg(color);
	int bb = - 255 + 2 * getr(color);

	float koef2r = (getb(color)) / 128.0;
	float koef2g = (getg(color)) / 128.0;
	float koef2b = (getr(color)) / 128.0;

	for (int i = 0; i < h; i++)
	{
		if (i+y < 0) continue;
		if (i+y >= height) break;
		for (int j = 0; j < w; j++)
		{
			if (j+x < 0) continue;
			if (j+x >= width) break;

//			COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]);
//			bits[(i+y)*width + (j+x)] = (cl > 128) ?
//				rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])):
//				rgba(koef2r * cl, koef2g * cl, koef2b * cl, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]));

			long alpha = geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]);
//			COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]);
			COLOR32 cl = alpha ? getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])*255/alpha : 0;
			COLOR32 src = (cl > 128) ?
				rgba(
					(koef1r * cl + br)*alpha/255,
					(koef1g * cl + bg)*alpha/255,
					(koef1b * cl + bb)*alpha/255,
					alpha):
				rgba(
					koef2r * cl * alpha/255,
					koef2g * cl * alpha/255,
					koef2b * cl * alpha/255,
					alpha);
//			COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]);
//			COLOR32 src = (cl > 128) ?
//				rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, alpha):
//				rgba(koef2r * cl, koef2g * cl, koef2b * cl, alpha);
			COLOR32 dst = bits[(i+y)*width + (j+x)];
//			long alpha = geta(src);
			bits[(i+y)*width + (j+x)] = rgba(
					getr(src)+(255-alpha)*getr(dst)/255,
					getg(src)+(255-alpha)*getg(dst)/255,
					getb(src)+(255-alpha)*getb(dst)/255,
					geta(src)+(255-alpha)*geta(dst)/255
				);

		}
	}
}
*/

/*
void MyBitmap::DrawColorized(MyBitmap *bmp, int x, int y, int w, int h, COLOR32 color)
{
	if (!(bits && bmp && bmp->bits)) return;

	if (!w) w = bmp->width;
	if (!h) h = bmp->height;
	float kx = (float)bmp->width / w;
	float ky = (float)bmp->height / h;

	// we should swap B and R channels when working with win32 COLORREF
	float koef1r = (255 - getb(color)) / 128.0;
	float koef1g = (255 - getg(color)) / 128.0;
	float koef1b = (255 - getr(color)) / 128.0;

	int br = - 255 + 2 * getb(color);
	int bg = - 255 + 2 * getg(color);
	int bb = - 255 + 2 * getr(color);

	float koef2r = (getb(color)) / 128.0;
	float koef2g = (getg(color)) / 128.0;
	float koef2b = (getr(color)) / 128.0;

	for (int i = 0; i < h; i++)
	{
		if (i+y < 0) continue;
		if (i+y >= height) break;
		for (int j = 0; j < w; j++)
		{
			if (j+x < 0) continue;
			if (j+x >= width) break;

			long alpha = geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]);
//			COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]);
			COLOR32 cl = alpha ? getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])*255/alpha : 0;
			bits[(i+y)*width + (j+x)] = (cl > 128) ?
				rgba(
					(koef1r * cl + br)*alpha/255,
					(koef1g * cl + bg)*alpha/255,
					(koef1b * cl + bb)*alpha/255,
					alpha):
				rgba(
					koef2r * cl * alpha/255,
					koef2g * cl * alpha/255,
					koef2b * cl * alpha/255,
					alpha);
//			bits[(i+y)*width + (j+x)] = (cl > 128) ?
//				rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])):
//				rgba(koef2r * cl, koef2g * cl, koef2b * cl, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]));
		}
	}
}
*/

/*
void MyBitmap::BlendPart(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h)
{
	if (!(bits && bmp && bmp->bits)) return;

	if (!w) w = win;
	if (!h) h = hin;
	float kx = (float)win / w;
	float ky = (float)hin / h;

	if (x+w >= this->getWidth())
		w = this->getWidth() - x;
	if (y+h >= this->getHeight())
		h = this->getHeight() - y;

	for (int i = 0; i < h; i++)
	{
		if (i+y < 0) continue;
		if (i+y >= height) break;
		for (int j = 0; j < w; j++)
		{
			if (j+x < 0) continue;
			if (j+x >= width) break;
			COLOR32 src = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)];
			COLOR32 dst = bits[(i+y)*width + (j+x)];
			long alpha = geta(src);
			bits[(i+y)*width + (j+x)] = rgba(
					getr(src)+(255-alpha)*getr(dst)/255,
					getg(src)+(255-alpha)*getg(dst)/255,
					getb(src)+(255-alpha)*getb(dst)/255,
					geta(src)+(255-alpha)*geta(dst)/255
				);
//			bits[(i+y)*width + (j+x)] = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)];
		}
	}
}
*/

/*
void MyBitmap::BlendPartColorized(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h, COLOR32 color)
{
	if (!(bits && bmp && bmp->bits)) return;

	if (!w) w = win;
	if (!h) h = hin;
	float kx = (float)win / w;
	float ky = (float)hin / h;

	if (x+w >= this->getWidth())
		w = this->getWidth() - x;
	if (y+h >= this->getHeight())
		h = this->getHeight() - y;

	// we should swap B and R channels when working with win32 COLORREF
	float koef1r = (255 - getb(color)) / 128.0;
	float koef1g = (255 - getg(color)) / 128.0;
	float koef1b = (255 - getr(color)) / 128.0;

	int br = - 255 + 2 * getb(color);
	int bg = - 255 + 2 * getg(color);
	int bb = - 255 + 2 * getr(color);

	float koef2r = (getb(color)) / 128.0;
	float koef2g = (getg(color)) / 128.0;
	float koef2b = (getr(color)) / 128.0;

	for (int i = 0; i < h; i++)
	{
		if (i+y < 0) continue;
		if (i+y >= height) break;
		for (int j = 0; j < w; j++)
		{
			if (j+x < 0) continue;
			if (j+x >= width) break;

			long alpha = geta(bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]);
//			COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]);
			COLOR32 cl = alpha ? getr(bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)])*255/alpha : 0;
			COLOR32 src = (cl > 128) ?
				rgba(
					(koef1r * cl + br)*alpha/255,
					(koef1g * cl + bg)*alpha/255,
					(koef1b * cl + bb)*alpha/255,
					alpha):
				rgba(
					koef2r * cl * alpha/255,
					koef2g * cl * alpha/255,
					koef2b * cl * alpha/255,
					alpha);
//			COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]);
//			COLOR32 src = (cl > 128) ?
//				rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, alpha):
//				rgba(koef2r * cl, koef2g * cl, koef2b * cl, alpha);
			COLOR32 dst = bits[(i+y)*width + (j+x)];
//			long alpha = geta(src);
			bits[(i+y)*width + (j+x)] = rgba(
					getr(src)+(255-alpha)*getr(dst)/255,
					getg(src)+(255-alpha)*getg(dst)/255,
					getb(src)+(255-alpha)*getb(dst)/255,
					geta(src)+(255-alpha)*geta(dst)/255
				);

			COLOR32 src = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)];
			COLOR32 dst = bits[(i+y)*width + (j+x)];
			long alpha = geta(src);
			bits[(i+y)*width + (j+x)] = rgba(
					getr(src)+(255-alpha)*getr(dst)/255,
					getg(src)+(255-alpha)*getg(dst)/255,
					getb(src)+(255-alpha)*getb(dst)/255,
					geta(src)+(255-alpha)*geta(dst)/255
				);
//			bits[(i+y)*width + (j+x)] = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)];
		}
	}
}
*/

/*
void MyBitmap::DrawPart(MyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h)
{
	if (!(bits && bmp && bmp->bits)) return;

	if (!w) w = win;
	if (!h) h = hin;
	float kx = (float)win / w;
	float ky = (float)hin / h;

	if (x+w >= this->getWidth())
		w = this->getWidth() - x;
	if (y+h >= this->getHeight())
		h = this->getHeight() - y;

	for (int i = 0; i < h; i++)
	{
		if (i+y < 0) continue;
		if (i+y >= height) break;
		for (int j = 0; j < w; j++)
		{
			if (j+x < 0) continue;
			if (j+x >= width) break;
			bits[(i+y)*width + (j+x)] = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)];
		}
	}
}
*/

/*
void MyBitmap::DrawNoAlpha(MyBitmap *bmp, int x, int y, int w, int h)
{
	if (!(bits && bmp && bmp->bits)) return;

	for (int i = 0; i < bmp->height; i++)
	{
		if (i+y < 0) continue;
		if (i+y >= height) break;
		for (int j = 0; j < bmp->width; j++)
		{
			if (j+x < 0) continue;
			if (j+x >= width) break;
			bits[(i+y)*width + (j+x)] = bmp->bits[i*bmp->width + j];
		}
	}
}
*/

/*
void MyBitmap::DrawIcon(HICON hic, int x, int y, int w, int h)
{
	ICONINFO info;
	GetIconInfo(hic, &info);

	BITMAP bmpColor, bmpMask;
	GetObject(info.hbmMask, sizeof(bmpMask), &bmpMask);
	GetObject(info.hbmColor, sizeof(bmpColor), &bmpColor);

	if (!w) w = abs(bmpMask.bmWidth);
	if (!h) h = abs(bmpMask.bmHeight);

	if (bmpColor.bmBitsPixel == 32)
	{
		if ((w != abs(bmpMask.bmWidth)) || (h != abs(bmpMask.bmHeight)))
		{
			DeleteObject(info.hbmColor);
			DeleteObject(info.hbmMask);
			hic = (HICON)CopyImage(hic,IMAGE_ICON,w,h,LR_COPYFROMRESOURCE);
			GetIconInfo(hic, &info);
			GetObject(info.hbmMask, sizeof(bmpMask), &bmpMask);
			GetObject(info.hbmColor, sizeof(bmpColor), &bmpColor);
		}

		BYTE *cbit = new BYTE[bmpColor.bmWidthBytes*bmpColor.bmHeight];
		BYTE *mbit = new BYTE[bmpMask.bmWidthBytes*bmpMask.bmHeight];
		GetBitmapBits(info.hbmColor, bmpColor.bmWidthBytes*bmpColor.bmHeight, cbit);
		GetBitmapBits(info.hbmMask, bmpMask.bmWidthBytes*bmpMask.bmHeight, mbit);

		for (int i = 0; i < bmpColor.bmHeight; i++)
		{
			for (int j = 0; j < bmpColor.bmWidth; j++)
			{
				BYTE *pixel = cbit + i*bmpColor.bmWidthBytes + j*4;
				if (!pixel[3])
				{
					pixel[3] = (*(mbit + i*bmpMask.bmWidthBytes + j*bmpMask.bmBitsPixel/8) & (1<<(7-j%8))) ? 0 : 255;
				}

				if (pixel[3] != 255)
				{
					pixel[0] = pixel[0] * pixel[3] / 255;
					pixel[1] = pixel[1] * pixel[3] / 255;
					pixel[2] = pixel[2] * pixel[3] / 255;
				}
			}
		}

		this->BlendBits((COLOR32 *)cbit, bmpColor.bmWidth, bmpColor.bmHeight, x, y, w, h);

		delete [] mbit;
		delete [] cbit;
	} else
	{
		this->saveAlpha(x,y,w,h);
		DrawIconEx(this->getDC(), x, y, hic, w, h, 0, NULL, DI_NORMAL);
		this->restoreAlpha(x,y,w,h);
	}

	DeleteObject(info.hbmColor);
	DeleteObject(info.hbmMask);
}
*/

void MyBitmap::DrawText(char *str, int x, int y)
{
	SIZE sz; GetTextExtentPoint32(this->getDC(), str, lstrlen(str), &sz);
	RECT rc; SetRect(&rc, x, y, x+10000, y+10000);
	this->saveAlpha(x-2,y-2,sz.cx+2,sz.cy+2);
	::DrawText(this->getDC(), str, strlen(str), &rc, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX);
	this->restoreAlpha(x-2,y-2,sz.cx+2,sz.cy+2);
	//(x,y,sz.cx,sz.cy);
}

/*
void MyBitmap::DrawTextW(WCHAR *str, int x, int y)
{
	if (MyGetTextExtentPoint32W && MyDrawTextW)
	{
		SIZE sz; MyGetTextExtentPoint32W(this->getDC(), str, MylstrlenW(str), &sz);
		RECT rc; SetRect(&rc, x, y, x+10000, y+10000);
		this->saveAlpha(x,y,sz.cx,sz.cy);
		MyDrawTextW(this->getDC(), str, MylstrlenW(str), &rc, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX);
		this->restoreAlpha(x,y,sz.cx,sz.cy);
	}
}
*/

HRGN MyBitmap::buildOpaqueRgn()
{
	return CreateRectRgn(0, 0, width, height);

	//
	int i, rectCount = 0;
	for (i = 0; i < width*height; i++)
		if ((bits[i] >> 24)&0xff >= 128)
			rectCount++;

	RGNDATA *rgnData = (RGNDATA *)malloc(sizeof(RGNDATAHEADER) + rectCount * sizeof(RECT));
	rgnData->rdh.dwSize = sizeof(RGNDATAHEADER);
	rgnData->rdh.iType = RDH_RECTANGLES;
	rgnData->rdh.nCount = rectCount;
	rgnData->rdh.nRgnSize = rectCount * sizeof(RECT);
	SetRect(&(rgnData->rdh.rcBound), 0, 0, width, height);

	char *p = (char *)&(rgnData->Buffer);
	for (i = 0; i < width*height; i++)
		if ((bits[i] >> 24)&0xff >= 128)
		{
			SetRect((LPRECT)p, i%width,i/width,i%width+1,i/width+1);
			p += sizeof(RECT);
		}

	HRGN rgn = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + rectCount * sizeof(RECT), rgnData);
	::free(rgnData);

	return rgn;
}

bool MyBitmap::loadFromFile(const char *fn, const char *fnAlpha)
{
	if (bits) free();

	SIZE sz;

	char ext[5];
	memcpy(ext,fn+(strlen(fn)-4),5);   

	if (!lstrcmpi(ext,".png"))
	{
		HANDLE hFile, hMap = NULL;
		BYTE* ppMap = NULL;
		long  cbFileSize = 0;
		BITMAPINFOHEADER* pDib;
		BYTE* pDibBits;
		
		if (!png2dibConvertor) {
			return false;
		}
		
		if ((hFile = CreateFileA(fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE)
			if ((hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL)
					if ((ppMap = (BYTE*)MapViewOfFile( hMap, FILE_MAP_READ, 0, 0, 0 )) != NULL)
						cbFileSize = GetFileSize(hFile, NULL);
		if ( cbFileSize != 0 )
		{
			PNG2DIB param;
			param.pSource = ppMap;
			param.cbSourceSize = cbFileSize;
			param.pResult = &pDib;
	
			if (png2dibConvertor((char*)param.pSource, param.cbSourceSize, param.pResult))
				pDibBits = (BYTE*)(pDib+1);
			else
				cbFileSize = 0;
			#ifdef _DEBUG
			logMessage("Loading splash file","done");
			#endif
			
		}

		if (ppMap) UnmapViewOfFile(ppMap);
		if (hMap) CloseHandle(hMap);
		if (hFile) CloseHandle(hFile);

		if (!cbFileSize) return false;

		BITMAPINFO *bi=(BITMAPINFO*)pDib;
		BYTE *pt=(BYTE*)bi;
		pt+=bi->bmiHeader.biSize;
		HBITMAP hBitmap;

		if (bi->bmiHeader.biBitCount!=32)
		{
			allocate(abs(bi->bmiHeader.biWidth), abs(bi->bmiHeader.biHeight));
			HDC hdcTmp = CreateCompatibleDC(getDC());
			HBITMAP hBitmap = CreateDIBitmap(getDC(), pDib, CBM_INIT, pDibBits, bi, DIB_PAL_COLORS);
			SelectObject(hdcTmp, hBitmap);
			BitBlt(this->getDC(), 0, 0, abs(bi->bmiHeader.biWidth), abs(bi->bmiHeader.biHeight), hdcTmp, 0, 0, SRCCOPY);
			this->makeOpaque();
			DeleteDC(hdcTmp);
			DeleteObject(hBitmap);

		}
		else
		{
				BYTE *ptPixels = pt;
				hBitmap = CreateDIBSection(NULL, bi, DIB_RGB_COLORS, (void **)&ptPixels, NULL, 0);         
				memcpy(ptPixels,pt,bi->bmiHeader.biSizeImage);

			allocate(abs(bi->bmiHeader.biWidth), abs(bi->bmiHeader.biHeight));
			//memcpy(bits, pt, bi->bmiHeader.biSizeImage);

			BYTE *p2=(BYTE *)pt;
			for (int y=0; y<bi->bmiHeader.biHeight; ++y)
			{
				BYTE *p1=(BYTE *)bits + (bi->bmiHeader.biHeight-y-1)*bi->bmiHeader.biWidth*4;
				for (int x=0; x<bi->bmiHeader.biWidth; ++x)
				{
					p1[0]= p2[0];
					p1[1]= p2[1];
					p1[2]= p2[2];
					p1[3]= p2[3];
					p1 += 4;
					p2 += 4;
				}
			}

			premultipleChannels();
		}

		GlobalFree(pDib);
		DeleteObject(hBitmap);
		return true;
	} else
	{
		HBITMAP hBmpLoaded = (HBITMAP)LoadImage(NULL, fn, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
		if (!hBmpLoaded)
		{
			#ifdef _DEBUG
			logMessage("MyBitmap::loadFromFile", "Bitmap load falied");
			#endif
			return false;
		}

		BITMAP bm; GetObject(hBmpLoaded, sizeof(bm), &bm);
		SetBitmapDimensionEx(hBmpLoaded, bm.bmWidth, bm.bmHeight, NULL);

		HDC dcTmp = CreateCompatibleDC(0);
		GetBitmapDimensionEx(hBmpLoaded, &sz);
		HBITMAP hBmpDcSave = (HBITMAP)SelectObject(dcTmp,  hBmpLoaded);

		allocate(sz.cx, sz.cy);
		BitBlt(dcBmp, 0, 0, width, height, dcTmp, 0, 0, SRCCOPY);

		DeleteObject(SelectObject(dcTmp, hBmpDcSave));
		DeleteDC(dcTmp);

		MyBitmap alpha;
		if (fnAlpha && alpha.loadFromFile(fnAlpha) &&
		    (alpha.getWidth() == width) &&
			(alpha.getHeight() == height) )
		{
			for (int i = 0; i < width*height; i++)
				bits[i] = (bits[i] & 0x00ffffff) | ( (alpha.bits[i] & 0x000000ff) << 24 );
			premultipleChannels();
		} else
		{
			makeOpaque();
		}
		return true;
	}
	// unreachable place
	return false;
}

void MyBitmap::allocate(int w, int h)
{
	width = w;
	height = h;

	BITMAPINFO bi;

    bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
    bi.bmiHeader.biWidth = w;
    bi.bmiHeader.biHeight = -h;
    bi.bmiHeader.biPlanes = 1;
    bi.bmiHeader.biBitCount = 32;
    bi.bmiHeader.biCompression = BI_RGB;

	if (dcBmp)
	{
		DeleteObject(SelectObject(dcBmp, hBmpSave));
		DeleteDC(dcBmp);
	}

    hBmp = (HBITMAP)CreateDIBSection(0, &bi, DIB_RGB_COLORS, (void **)&bits, 0, 0);
    dcBmp = CreateCompatibleDC(0);
    hBmpSave = (HBITMAP)SelectObject(dcBmp, hBmp);
}

void MyBitmap::free()
{
	DeleteObject(SelectObject(dcBmp, hBmpSave));
	DeleteDC(dcBmp);

	dcBmp = 0;
	hBmp = 0;
	bits = 0;
	width = height = 0;
}

void MyBitmap::premultipleChannels()
{
	for (int i = 0; i < width*height; i++)
		bits[i] = rgba(getr(bits[i])*geta(bits[i])/255, getg(bits[i])*geta(bits[i])/255, getb(bits[i])*geta(bits[i])/255, geta(bits[i]));
}